package com.xuecheng.ucenter.service.impl;

import com.alibaba.fastjson.JSON;
import com.xuecheng.ucenter.mapper.XcMenuMapper;
import com.xuecheng.ucenter.model.dto.AuthParamsDto;
import com.xuecheng.ucenter.model.dto.XcUserExt;
import com.xuecheng.ucenter.model.po.XcMenu;
import com.xuecheng.ucenter.service.AuthService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * 自定义UserDetailsService用来对接Spring Security
 */
@Slf4j
@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    // Spring容器（策略模式：用于实现一个Service接口有多个实现类的情况下的调用）
    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    XcMenuMapper xcMenuMapper;


    /**
     * 查询用户信息，组成用户身份信息
     *
     * @param username AuthParamsDto类型的json认证数据
     * @return 用户信息
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 参数类型
        AuthParamsDto authParamsDto;
        try {
            // 将json类型的参数转换为AuthParamsDto类型
            authParamsDto = JSON.parseObject(username, AuthParamsDto.class);
        } catch (Exception e) {
            log.error("认证请求参数不符合要求：{}", username);
            throw new RuntimeException("认证请求参数不符合要求");
        }

        // 开始认证
        // 获取认证类型（password、wx）
        String authType = authParamsDto.getAuthType();
        // 通过Spring容器对象根据Bean名称进行调用
        AuthService authService = applicationContext.getBean(authType + "_auth_service", AuthService.class);
        // 获取用户信息
        XcUserExt user = authService.execute(authParamsDto);
        // 组装用户详情信息并返回
        return getUserDetails(user);
    }

    /**
     * 组装用户详情信息
     *
     * @param user 用户信息
     * @return 用户详情信息
     */
    private UserDetails getUserDetails(XcUserExt user) {
        // 获取用户id
        String userId = user.getId();
        // 获取密码(用于最终封装到UserDetails对象中，返回给Spring Security框架，帮我们做密码比对)
        String password = user.getPassword();

        // 根据用户id获取用户权限列表
        List<XcMenu> xcMenus = xcMenuMapper.selectPermissionByUserId(userId);
        List<String> authorities = new ArrayList<>();
        xcMenus.forEach(menu -> {
            authorities.add(menu.getCode());
        });

        // 封装用户信息到令牌中
        // 密码不封装到令牌中
        user.setPassword(null);
        // 用户权限
        user.setPermissions(authorities);
        // 转为json格式
        String userInfo = JSON.toJSONString(user);

        // 构建用户详情结果
        UserDetails userDetails = User.withUsername(userInfo).password(password).authorities(String.valueOf(authorities)).build();
        // 返回用户详情结果
        return userDetails;
    }
}
